package com.file.parser;


import com.file.bo.ResponseData;
import com.file.bo.mail.AliPay;
import com.file.bo.mail.AliPayTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class AlipayPdfParser extends BasePdfParser{

	public ResponseData<String> parseAliPayPdfToJson(String daId, String filePath) {
		log.info("parseAliPayPdfToJson started, daId:{}", daId);
		String json = null;

		try {
			AliPay alipay = parseAliPayPdf(filePath);
			json = JsonUtils.convertObjectToJson(alipay);
			doAlert(daId, alipay);
		} catch (Exception e) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson failed", e);
			return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
		}

		log.info("parseAliPayPdfToJson completed, daId:{}", daId);
		return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
	}

	public AliPay parseAliPayPdf(String filePath) {
		List<AliPayTran> aliPayTrans = parseTrans(filePath);

		AliPay alipay = parseAliPayHeader(filePath);

		alipay.setAliPayTrans(aliPayTrans);

		return alipay;
	}

	public AliPay parseAliPayHeader(String filePath) {
		AliPay alipay = new AliPay();
		String pdfHeaderText = parsePdfHeaderText(filePath);

		String number = pdfHeaderText.substring(pdfHeaderText.indexOf("编号:") + 3, pdfHeaderText.indexOf("支付宝（中国）网络技术有限公司")).trim();
		String name = pdfHeaderText.substring(pdfHeaderText.indexOf("兹证明") + 4, pdfHeaderText.indexOf("(证件号码")).trim();
		String idNumber = pdfHeaderText.substring(pdfHeaderText.indexOf("证件号码:") + 5, pdfHeaderText.indexOf(")在其支付宝账号")).trim();
		String aliPayAccount = pdfHeaderText.substring(pdfHeaderText.indexOf(")在其支付宝账号") + 8, pdfHeaderText.indexOf("中明细信息如")).trim();
		String currency = pdfHeaderText.substring(pdfHeaderText.indexOf("币种：") + 3, pdfHeaderText.indexOf("/ 单位")).trim();
		String unit = pdfHeaderText.substring(pdfHeaderText.indexOf("单位：") + 3, pdfHeaderText.indexOf("交易时间段：")).trim();
		String transDetailPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("交易时间段：") + 6, pdfHeaderText.indexOf("交易类型：")).trim();
		String tranType = pdfHeaderText.substring(pdfHeaderText.indexOf("交易类型：") + 5, pdfHeaderText.indexOf("收/支")).trim();
		alipay.setNumber(number);
		alipay.setName(name);
		alipay.setIdNumber(idNumber);
		alipay.setCurrency(currency);
		alipay.setUnit(unit);
		alipay.setAliPayAccount(aliPayAccount);
		alipay.setTransDetailPeriod(transDetailPeriod);
		alipay.setTranType(tranType);
		return alipay;
	}

	public List<AliPayTran> parseTrans(String filePath) {
		List<AliPayTran> aliPayTrans = new ArrayList<>();

		// 1. 读取文件
		File pdf = new File(filePath);

		// 2. pdfbox读取PDDocument
		try (PDDocument pdfDocument = PDDocument.load(pdf)) {

			// 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
			ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
			NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
			Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

			// 4. 获取每页的PageIterator
			PageIterator pages = objectExtractor.extract();

			// 5. 解析每页的Rectangle(table的位置)
			while (pages.hasNext()) {
				Page page = pages.next();
				List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
				if (tablesOnPage.size() > 0) {
					detectedTables.put(Integer.valueOf(page.getPageNumber()), tablesOnPage);
				}
			}

			// 6.通过table位置获取表格具体内容
			SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

			String excludeColumn = null;

			// 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
			for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
				Page page = objectExtractor.extract(entry.getKey());

				// 支付宝默认每页只有一个表格，因此获取第0个rectangle
				Rectangle rectangle = entry.getValue().get(0);
				Page area = page.getArea(rectangle.getTop(), rectangle.getLeft(),rectangle.getBottom(),rectangle.getRight());

				List<Table> table = bea.extract(area);

				// 支付宝默认每页只有一个表格，因此获取第0个table
				Table t = table.get(0);

				if (t.getColCount() < 6 || t.getColCount() > 8) {
					log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), "", "", "", "Alipay Pdf format changed");
					throw new RuntimeException();
				}


				// 解析第一页时，去掉表头三行数据
				if (entry.getKey() == 1) {
					for (int i = 0; i < t.getRowCount(); i++) {
						if (t.getColCount() == 7 && t.getCell(i,1).getText(false).contains("商品说明")) {
							excludeColumn = "conterParty";
						} else if (t.getColCount() == 7 && t.getCell(i,2).getText(false).contains("收/付款方式")) {
							excludeColumn = "productDescription";
						}

						if (t.getCell(i,0).getText(false).contains("交易时间段")
								|| t.getCell(i,0).getText(false).contains("交易类型")
								|| t.getCell(i,0).getText(false).contains("收/支")) {
							continue;
						}
						AliPayTran aliPayTran = getTransactionByTable(t, i, excludeColumn);
						if (StringUtils.isNotBlank(aliPayTran.getIncomeOrExpense())) {
							aliPayTrans.add(aliPayTran);
						}
					}
				} else {
					for (int i = 0; i < t.getRowCount(); i++) {
						AliPayTran aliPayTran = getTransactionByTable(t, i, excludeColumn);
						if (StringUtils.isNotBlank(aliPayTran.getIncomeOrExpense())) {
							aliPayTrans.add(aliPayTran);
						}
					}
				}
			}
		}  catch (Exception e) {
			throw new RuntimeException(e);
		}

		return aliPayTrans;
	}

	private AliPayTran getTransactionByTable(Table t, int i, String excludeColumn) {
		AliPayTran aliPayTran = new AliPayTran();
		if (t.getColCount() == 8) {
			aliPayTran.setIncomeOrExpense(t.getCell(i,0).getText(false));
			aliPayTran.setCounterParty(t.getCell(i,1).getText(false));
			aliPayTran.setProductDescription(t.getCell(i,2).getText(false));
			aliPayTran.setPaymentMethod(t.getCell(i,3).getText(false));
			aliPayTran.setAmt(t.getCell(i,4).getText(false));
			aliPayTran.setTranOrderNo(t.getCell(i,5).getText(false));
			aliPayTran.setMerchantOrderNo(t.getCell(i,6).getText(false));
			aliPayTran.setTranDate(t.getCell(i,7).getText(false));
		} else if (t.getColCount() == 6) {
			aliPayTran.setIncomeOrExpense(t.getCell(i,0).getText(false));
			aliPayTran.setPaymentMethod(t.getCell(i,1).getText(false));
			aliPayTran.setAmt(t.getCell(i,2).getText(false));
			aliPayTran.setTranOrderNo(t.getCell(i,3).getText(false));
			aliPayTran.setMerchantOrderNo(t.getCell(i,4).getText(false));
			aliPayTran.setTranDate(t.getCell(i,5).getText(false));
			aliPayTran.setCounterParty("");
			aliPayTran.setProductDescription("");
		} else if (t.getColCount() == 7) {
			if (StringUtils.equals(excludeColumn, "conterParty")) {
				aliPayTran.setIncomeOrExpense(t.getCell(i,0).getText(false));
				aliPayTran.setProductDescription(t.getCell(i,1).getText(false));
				aliPayTran.setPaymentMethod(t.getCell(i,2).getText(false));
				aliPayTran.setAmt(t.getCell(i,3).getText(false));
				aliPayTran.setTranOrderNo(t.getCell(i,4).getText(false));
				aliPayTran.setMerchantOrderNo(t.getCell(i,5).getText(false));
				aliPayTran.setTranDate(t.getCell(i,6).getText(false));
				aliPayTran.setCounterParty("");
			} else if (StringUtils.equals(excludeColumn, "productDescription")) {
				aliPayTran.setIncomeOrExpense(t.getCell(i,0).getText(false));
				aliPayTran.setCounterParty(t.getCell(i,1).getText(false));
				aliPayTran.setPaymentMethod(t.getCell(i,2).getText(false));
				aliPayTran.setAmt(t.getCell(i,3).getText(false));
				aliPayTran.setTranOrderNo(t.getCell(i,4).getText(false));
				aliPayTran.setMerchantOrderNo(t.getCell(i,5).getText(false));
				aliPayTran.setTranDate(t.getCell(i,6).getText(false));
				aliPayTran.setProductDescription("");
			}
		}


		return aliPayTran;
	}

	private void doAlert(String daId, AliPay alipay) {
		log.info("doAlert started daId: {}", daId);
		//加入字段告警
		if (StringUtils.isBlank(alipay.getNumber())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay Number is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(alipay.getName())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay Name is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(alipay.getIdNumber())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay IdNumber is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(alipay.getCurrency())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay Currency is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(alipay.getUnit())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay Unit is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(alipay.getAliPayAccount())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay AliPayAccount is null");
			throw new RuntimeException();
		}
		if (StringUtils.isBlank(alipay.getTransDetailPeriod())) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson alipay TransDetailPeriod is null");
			throw new RuntimeException();
		}

		List<AliPayTran> aliPayTrans = alipay.getAliPayTrans();
		if (aliPayTrans.size() == 0) {
			log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson aliPayTrans size is 0");
		}

		for (AliPayTran aliPayTran : aliPayTrans) {
			if (StringUtils.isBlank(aliPayTran.getIncomeOrExpense())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson aliPayTran IncomeOrExpense is null");
				throw new RuntimeException();
			}
			if (StringUtils.isBlank(aliPayTran.getAmt())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson aliPayTran Amt is null");
				throw new RuntimeException();
			}
			if (StringUtils.isBlank(aliPayTran.getTranDate())) {
				log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_NULL_ALERT_EXCEPTION.getCode(), daId, "", "", "parseAliPayPdfToJson aliPayTran TranDate is null");
				throw new RuntimeException();
			}
		}
	}

	public static void main(String[] args) {
		AlipayPdfParser alipayPdfParser = new AlipayPdfParser();
		AliPay aliPay = alipayPdfParser.parseAliPayPdf("D:\\data\\file\\alipay\\372746394995265302_842946517a14cd9197db13b513bba9f2_流水证明_202109130008500490284891886386004417582.pdf");
		System.out.println(JsonUtils.convertObjectToJson(aliPay));

//		AliPay aliPay = alipayPdfParser.parseAliPayPdf("D:\\data\\file\\alipay\\流水证明_2022081500085004002321723327320046866434-6.pdf");
//		System.out.println(JsonUtils.convertObjectToJson(aliPay));

//		AliPay aliPay = alipayPdfParser.parseAliPayPdf("D:\\data\\file\\alipay\\流水证明_202208150008500400232172332732004682085-7-noparty.pdf");
//		System.out.println(JsonUtils.convertObjectToJson(aliPay));

	}

}
